﻿//TODO: OutlineEdges: test

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Outlines edges of a bitmap
    /// </summary>
    public class OutlineEdges : BaseImageFilter
    {
        protected int m_nNoise = 0;
        protected Color m_Color = Color.Transparent;

        /// <summary>
        /// Initializes a new instance of the <see cref="OutlineEdges"/> class.
        /// </summary>
        public OutlineEdges()
            : this(2, Color.Gray)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="OutlineEdges"/> class.
        /// </summary>
        /// <param name="_nNoise">The _n noise.</param>
        /// <param name="_color">The _color.</param>
        public OutlineEdges(int _nNoise, Color _color)
        {
            m_nNoise = _nNoise;
            m_Color = _color;
        }

        /// <summary>
        /// Used to clone this instance
        /// </summary>
        /// <param name="_outlineEdges"></param>
        internal OutlineEdges(OutlineEdges _outlineEdges)
        {
            m_nNoise = _outlineEdges.m_nNoise;
            m_Color = _outlineEdges.m_Color;
        }

        /// <summary>
        /// Gets or sets the noise.
        /// </summary>
        /// <value>The noise.</value>
        public int Noise
        {
            get { return m_nNoise; }
            set { m_nNoise = value; }
        }

        /// <summary>
        /// Gets or sets the color.
        /// </summary>
        /// <value>The color.</value>
        public Color Color
        {
            get { return m_Color; }
            set { m_Color = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            UnsafeBitmap modified = _bitmap;
            Graphics g = Graphics.FromImage(_bitmap.InternalBitmap);

            Int32 x = 0;
            Int32 y = 0;

            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;

            Color current = Color.Transparent;
            Color right = Color.Transparent;
            Color left = Color.Transparent;

            Color upRight = Color.Transparent;
            Color downLeft = Color.Transparent;
            Color upOne = Color.Transparent;
            Color downOne = Color.Transparent;
            Color upLeft = Color.Transparent;
            Color downRight = Color.Transparent;

            int totalCurrent = 0;
            int totalRight = 0;
            int totalLeft = 0;

            for (x = 1; x < nWidth - 1; x++)
            {
                for (y = 1; y < nHeight - 1; y++)
                {
                    current = modified.GetPixel(x, y);
                    right = modified.GetPixel(x + 1, y);
                    left = modified.GetPixel(x - 1, y);

                    totalCurrent = current.R + current.G + current.B;
                    totalRight = right.R + right.G + right.B;
                    totalLeft = left.R + left.G + left.B;

                    if (totalCurrent > (totalLeft + m_nNoise) || totalCurrent > (totalRight + m_nNoise))
                    {
                        modified.SetPixel(x - 1, y, m_Color);
                    }
                    else if (totalCurrent > (totalRight + m_nNoise))
                    {
                        modified.SetPixel(x + 1, y, m_Color);
                    }

                    upOne = modified.GetPixel(x, y - 1);
                    downOne = modified.GetPixel(x, y + 1);

                    int totalUpOne = upOne.R + upOne.G + upOne.B;
                    int totalDownOne = downOne.R + downOne.G + downOne.B;

                    if (totalUpOne > (totalCurrent + m_nNoise)) //|| totalDownOne > (totalCurrent + 75))
                    {
                        modified.SetPixel(x, y - 1, m_Color);
                    }
                    else if (totalDownOne > (totalCurrent + m_nNoise))
                    {
                        modified.SetPixel(x, y + 1, m_Color);
                    }

                    upLeft = modified.GetPixel(x - 1, y - 1);
                    downRight = modified.GetPixel(x + 1, y + 1);

                    int totalUpLeft = upLeft.R + upLeft.G + upLeft.B;
                    int totalDownRight = downRight.R + downRight.G + downRight.B;
                    if (totalUpLeft > (totalCurrent + m_nNoise))
                    {
                        modified.SetPixel(x - 1, y - 1, m_Color);
                    }
                    else if (totalDownRight > (totalCurrent + m_nNoise))
                    {
                        modified.SetPixel(x + 1, y + 1, m_Color);
                    }

                    upRight = modified.GetPixel(x + 1, y - 1);
                    downLeft = modified.GetPixel(x - 1, y + 1);

                    int totalupRight = upRight.R + upRight.G + upRight.B;
                    int totalDownLeft = downLeft.R + downLeft.G + downLeft.B;
                    if (totalupRight > (totalCurrent + m_nNoise))
                    {
                        modified.SetPixel(x + 1, y - 1, m_Color);
                    }
                    else if (totalDownRight > (totalCurrent + m_nNoise))
                    {
                        modified.SetPixel(x - 1, y + 1, m_Color);
                    }

                }
            }
            modified.Dispose();
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new OutlineEdges(this);
        }
    }
}
